
package stcu;

import com.nvlled.route.*;
import stcu.robjects.*;
import java.util.*;
import java.net.*;

public class ClientAuth {

    private static final String NO_SERVER = "No server found";
    private static final long LOGIN_TIMEOUT = 3000; // milliseconds
    private static final int MAX_SERVER = 10;

    private ObjectRouter router;
    private Prober prober;
    private boolean loggingIn;
    private boolean authenticated = false;
    private Account account = Account.VOID;
	private String serverName;
    private List<Listener> listeners;

    public ClientAuth(ObjectRouter router) {
        this.router = router;
        listeners = new LinkedList<Listener>();
    }

    public void addListener(Listener listener) {
        if (listener != null) {
            listeners.add(listener);
        }
    }

	public String getServerName(){
		return serverName;
	}

    private void loginSuccess(Login.Status status) {
        AddressTable table =  router.getTable();
        serverName = table.getName(status.getSourceAddress());
        table.store("default", status.getSourceAddress());
        authenticated = true;
        account = status.getAccount();

        for (Listener listener: listeners) {
            listener.success(status);
        }
    }

    public String getLoginId() {
        return account.getIDNumber();
    }

    public Account getAccount() {
        return account;
    }

    public boolean isAuthenticated() {
        return authenticated;
    }

    private List<Login.Status> sendLoginData(String username) {
        RequestInfo info = new RequestInfo(
                Login.Status.class, MAX_SERVER,
                LOGIN_TIMEOUT, false);

        Login login = new Login(username);
        return router.deliverSync(login, info, getServerNames());
        
    }

    public void login(String username) {
        List<Login.Status> statuses = sendLoginData(username);

        if (statuses.isEmpty()) {
            for (Listener listener: listeners) {
                listener.fail(NO_SERVER);
            }
            return;
        }

        Login.Status successStat = null;
        Login.Status failStat = null;
        for(Login.Status stat: statuses) {
            String msg = stat.getCode();
            if (stat.isOK()) {
                successStat = stat;
                break;
            } else if (msg.equals(Login.LOGGED_IN)){
                failStat = stat;
            }
        }

        if (successStat != null) {
            loginSuccess(successStat);
        } else {
            String code = 
                ( failStat != null )
                ? failStat.getCode()
                : Login.INVALID_USER;

            for (Listener listener: listeners) {
                listener.fail(code);
            }
        }
    }

    private List<String> getServerNames() {
        List<String> names = new ArrayList<String>();
        AddressTable table = router.getTable();
        for(String name: table.getNames()) {
            if (name.startsWith(Prober.SERVER_PREFIX)) {
                names.add(name);
            }
        }
        return names;
    }

    public void logout() {
        if (authenticated) {
            account = Account.VOID;
            authenticated = false;
            router.deliver(new Logout(), "default");
            for (Listener listener: listeners) {
                listener.logout();
            }
        }
    }

    
    public static interface Listener {
        public void fail(String msg);

        public void success(Login.Status status);

        public void logout();
    }
}

